package com.qf.ability.gateway.filter;

import com.qf.ability.gateway.util.ResponseUtils;
import com.qf.commons.event.apply.producer.EventUtils;
import com.qf.data.base.r.Codes;
import com.qf.data.base.r.R;
import com.qf.data.base.r.Rs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 抢红包的过滤器 - 局部过滤器
 * description:
 * author: Ken
 * 公众号：Java架构栈
 */
@Slf4j
@Component
public class RedEnvelopesFilter extends AbstractGatewayFilterFactory implements Ordered {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 抢红包的lua脚本
     */
    private String luaRedRob = "--抢红包的lua脚本\n" +
            "--红包id\n" +
            "local redid = KEYS[1]\n" +
            "--用户id\n" +
            "local uid = ARGV[1]\n" +
            "--组装操作红包的key\n" +
            "local key = \"red_envelopes_\"..redid\n" +
            "\n" +
            "--判断，当前红包是否存在\n" +
            "local flag = redis.call(\"exists\", key)\n" +
            "if flag == 0 then\n" +
            "   -- 红包不存在，非法的参数或者红包已经过期\n" +
            "   return  -1\n" +
            "end\n" +
            "\n" +
            "\n" +
            "--获取红包的一些参数\n" +
            "local hasScore = tonumber(redis.call(\"hget\", key, \"hasScore\"))\n" +
            "local hasCount = tonumber(redis.call(\"hget\", key, \"hasCount\"))\n" +
            "local type = tonumber(redis.call(\"hget\", key, \"type\"))\n" +
            "\n" +
            "--判断，红包是否已经抢完\n" +
            "if hasCount == 0 then\n" +
            "    -- 红包已经抢完了\n" +
            "    return -2\n" +
            "end\n" +
            "\n" +
            "--判断，判断当前用户是否已经抢过\n" +
            "local flag2 = redis.call(\"hexists\", key, \"user_\"..uid)\n" +
            "if flag2 == 1 then\n" +
            "   -- 已经抢过该红包了\n" +
            "   return -3\n" +
            "end\n" +
            "\n" +
            "--开始计算抢红包的值\n" +
            "local robScore = 0\n" +
            "\n" +
            "if type == 0 then\n" +
            "   -- 固定红包\n" +
            "   robScore = hasScore / hasCount\t\n" +
            "else\n" +
            "   -- 随机红包\n" +
            "   if hasCount == 1 then\n" +
            "       -- 最后一个名额\n" +
            "       robScore = hasScore \n" +
            "   else \n" +
            "       -- 不是最后一个名额  \n" +
            "       local times = redis.call(\"time\")\n" +
            "       math.randomseed(times[1] + times[2])\n" +
            "       robScore = math.random(hasScore / hasCount * 2 - 1)\n" +
            "   end\t\n" +
            "end\n" +
            "\n" +
            "--修改redis中的相关数值\n" +
            "redis.call(\"hset\", key, \"hasScore\",  hasScore - robScore)\n" +
            "redis.call(\"hset\", key, \"hasCount\", hasCount - 1)\n" +
            "redis.call(\"hset\", key, \"user_\"..uid, robScore)\n" +
            "\n" +
            "--返回抢走的积分数\n" +
            "return robScore";

    @Override
    public GatewayFilter apply(Object config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                //局部过滤器的执行代码
                log.info("[red rob filter] - 抢红包的局部过滤器生效！");

                //获取请求参数 - 红包id 用户id
                ServerHttpRequest request = exchange.getRequest();
                String redid = request.getQueryParams().getFirst("redid");
                log.info("[red rob filter] - 获取拼抢的红包id - {}", redid);

                String uid = request.getHeaders().getFirst("uid");
                if (uid == null) {
                    uid = (int)(Math.random() * 10000) + 1 + "";
                }
                log.info("[red rob filter] - 获取拼抢的用户id - {}", uid);

                if (redid == null || uid == null)
                    return ResponseUtils.createResponse(Rs.createFail(Codes.PARAM_ERROR), exchange, HttpStatus.BAD_REQUEST);

                //执行lua脚本
                long result = redisTemplate.execute(new DefaultRedisScript<>(luaRedRob, Long.class),
                        Collections.singletonList(redid),
                        uid);

                //准备一个R对象，返回给客户端
                R rs = null;
                if (result > 0) {
                    //抢到积分

                    //将当前的相关信息，通过事件总线，告知红包服务，红包服务同步到数据库中（最终一致性）
                    Map content = new HashMap<>();
                    content.put("redid", redid);
                    content.put("uid", uid);
                    content.put("score", result);
                    EventUtils.send("rob_red_event", content);

                    rs = Rs.create(result);
                } else if (result == -1) {
                    //红包不存在或者已经过期
                    rs = Rs.createFail(Codes.ROB_RED_NULL);
                } else if (result == -2) {
                    //红包已经抢完
                    rs = Rs.createFail(Codes.ROB_RED_OVER);
                } else if (result == -3) {
                    //已经抢过了
                    rs = Rs.createFail(Codes.ROB_RED_HAS);
                }

                //直接响应给用户
                return ResponseUtils.createResponse(rs, exchange, HttpStatus.OK);
            }
        };
    }

    @Override
    public String name() {
        return "redEvnelopesFilter";
    }

    @Override
    public int getOrder() {
        return 100;
    }
}
